This section covers how to download historical financial data for stocks and indexes, how the manipulate and format this data, a number of different visualization techniques, and how to analyze the collected data in various ways.
# These commands are for Azure users to run. Uncomment the following to have them enabled when running this cell.
# !pip install pandas_datareader
# !pip install pyfinance
# !pip install fix_yahoo_finance
# !pip install --upgrade pandas
# !pip install quandl
# !pip install statsmodels
import pandas as pd
import numpy as np
import datetime
from datetime import datetime
from pandas_datareader import data as web
# https://pypi.python.org/pypi/fix-yahoo-finance
import fix_yahoo_finance as yf
import matplotlib.pyplot as plt
%matplotlib inline
# Formatting display options.
plt.style.use('default')
pd.set_option('display.notebook_repr_html', True)
pd.set_option('display.max_rows', 15)
pd.set_option('precision', 5)
yf.pdr_override()
# Note:
# If data is not being downloaded then consider restarting the kernel and running all cells again.
The following commands will obtain the historical quotes for Nvidia (NVDA) from 1/1/2005 to 12/31/2015.
start = datetime(2005, 1, 1)
end = datetime(2015, 12, 31)
nvda = web.get_data_yahoo('NVDA', start, end)
# Show the first five dates and accompanying information.
nvda.head()
Acquiring historical quotes from different companies in various industry sectors and storing that information in a DataFrame for later analysis use.
# This function will obtain the quotes for a list of stock tickers and return the results in a single DataFrame.
def get(tickers, start, end):
def data(ticker):
return web.get_data_yahoo(ticker, start, end)
datas = [data(ticker) for ticker in tickers]
return pd.concat(datas, keys=tickers, names=['Ticker', 'Date'])
The following is a selection of sectors that contain some proposed companies with varying performances. The analysis later on will determine if these assertions are true given the time period of collected data mentioned before.
High Performance: HAL - Halliburton Company
Low Performance: APA - Apache Corporation
Average Performance: CVX - Chevron Corporation
Average Performance: XOM - Exxon Mobil Corporation
High Performance: NVDA - Nvidia
Low Performance: CSCO - Cisco Systems
Average Performance: ADSK - Autodesk
Average Performance: ADBE - Adobe Systems
High Performance: ABT - Abbott Laboratories
Low Performance: ZBH - Zimmer Biomet Holdings
Average Performance: JNJ - Johnson & Johnson
Average Performance: BAX - Baxter International Incorporated
# Download the relevant data for all of the companies listed.
tickers = ['NVDA', 'CSCO', 'ADSK', 'ADBE', 'HAL', 'APA', 'CVX', 'XOM', 'ABT', 'ZBH', 'JNJ', 'BAX']
stocks_data = get(tickers, start, end)
stocks_data.head()
stocks_data.tail()
Acquiring historical data from the Standard & Poor's 500 Index.
sp500 = web.get_data_yahoo('^GSPC', start, end)
sp500.head()
Extract and store the adjusted closing values for each stock.
# Select the Adj Close column and reset the index to move the dates.
adj_closing_prices = stocks_data[['Adj Close']].reset_index()
# Display the first ten rows for the adjusted closing values.
adj_closing_prices[:10]
# Pivot the Date values into the index and the Ticker values into a column.
daily_adj_closing_prices = adj_closing_prices.pivot('Date', 'Ticker', 'Adj Close')
# Display the first five daily adjusted closing prices for all companies.
daily_adj_closing_prices.head()
# Select a company's specific column to plot a single stock's adjusted closing price.
daily_adj_closing_prices['NVDA'].plot(figsize=(20, 8));
# The ";" character is included at the end to suppress any unnecessary text output.
# Executing the commands sequentially will result in one graph that includes the specified stocks.
daily_adj_closing_prices['HAL'].plot(figsize=(20, 8), grid=True) # Adds grid
daily_adj_closing_prices['APA'].plot(figsize=(20, 8), grid=True)
daily_adj_closing_prices['CVX'].plot(figsize=(20, 8), grid=True)
daily_adj_closing_prices['XOM'].plot(figsize=(20, 8), grid=True);
# Alternative:
# Daily adjusted closing prices for the information technology sector.
information_technology_sector = daily_adj_closing_prices[['NVDA', 'CSCO', 'ADSK', 'ADBE']].copy()
# Display the sector data.
information_technology_sector.plot(figsize=(20, 12), grid=True)
plt.title('Information Technology Sector Daily Adjusted Closing Prices (NVDA, CSCO, ADSK, ADBE) from 2005 - 2015');
# Plot all of the adjusted closing prices for every stock in the DataFrame.
daily_adj_closing_prices.plot(figsize=(30, 25), grid=True); # figsize values can be modified to adjust sizing.
# Use %matplotlib notebook before the plot function to display an interactive chart.
# If this does not work as intended then execute 'conda install pyqt' in your Anaconda Prompt.
# %matplotlib inline will return charts back to normal.
The following commands will allow the plotting of volume-series data for a specified stock.
nvdaVolume = stocks_data.Volume.loc['NVDA']
plt.bar(nvdaVolume.index, nvdaVolume)
plt.gcf().set_size_inches(20, 8)
Plotting a stock's trading volume relative to its adjusted closing price.
top = plt.subplot2grid((4, 4), (0, 0), rowspan = 3, colspan = 4)
top.plot(daily_adj_closing_prices.index, daily_adj_closing_prices.NVDA, label = 'Adjusted Close')
top.grid(True)
plt.title('NVDA Adjusted Close Prices from 2005 - 2015')
plt.legend(loc = 2)
bottom = plt.subplot2grid((4, 4), (3, 0), rowspan = 1, colspan = 4)
bottom.bar(nvdaVolume.index, nvdaVolume)
bottom.grid(True)
plt.title('Nvidia Daily Trading Volumes')
plt.gcf().set_size_inches(20, 10)
plt.subplots_adjust(hspace = 0.75)
These charts are used to illustrate price movments of a stock over time.
Information on these types of charts: http://stockcharts.com/school/doku.php?id=chart_school:chart_analysis:introduction_to_candlesticks
# Obtain subset data for Nvidia from December 2012.
subset_data = stocks_data.loc['NVDA'].loc['2012-12':'2012-12'].reset_index()
subset_data
The data must now be formatted in a couple ways before it can used as an input.
# Date formatting.
import matplotlib.dates as mdates
subset_data['date_num'] = subset_data.Date.apply(lambda date: mdates.date2num(date.to_pydatetime()))
subset_data
# Formatting subset_data into a list of tuples.
tuples_subset_data = [tuple(x) for x in subset_data[['date_num', 'Open', 'High', 'Low', 'Close']].values]
tuples_subset_data
Format the x-axis before plotting.
Documentation: https://matplotlib.org/api/dates_api.html
# Specifies the weekly format on the x-axis.
from matplotlib.dates import DateFormatter
week_format = DateFormatter('%b %d')
# Specifies the days that should be labeled on the x-axis. In this case mondays.
from matplotlib.dates import WeekdayLocator, MONDAY
mondays_locator = WeekdayLocator(MONDAY)
from matplotlib.finance import candlestick_ohlc
# Plot the candlestick chart.
figure, axis = plt.subplots(figsize=(20, 12))
axis.xaxis.set_major_locator(mondays_locator)
axis.xaxis.set_major_formatter(week_format)
axis.yaxis.grid(color='black', linestyle='--', linewidth=.2)
candlestick_ohlc(axis, tuples_subset_data, width=0.5, colorup='g', colordown='r');
# Display data for Nvidia from October to December in 2010.
subset_data = stocks_data.loc['NVDA'].loc['2010-10':'2010-12'].reset_index()
subset_data['date_num'] = subset_data.Date.apply(lambda date: mdates.date2num(date.to_pydatetime()))
tuples_subset_data = [tuple(x) for x in subset_data[['date_num', 'Open', 'High', 'Low', 'Close']].values]
week_format = DateFormatter('%b %d')
mondays_locator = WeekdayLocator(MONDAY)
figure, axis = plt.subplots(figsize=(20, 12))
axis.xaxis.set_major_locator(mondays_locator)
axis.xaxis.set_major_formatter(week_format)
axis.yaxis.grid(color='black', linestyle='--', linewidth=.2)
candlestick_ohlc(axis, tuples_subset_data, width=0.5, colorup='g', colordown='r');
The following will determine the percentage change in the value of a stock over one day.
# Calculate the adjusted closing price percentage change for NVDA between 2005-01-03 and 2005-01-04.
NVDA_p1 = daily_adj_closing_prices.iloc[0]['NVDA'] # 2005-01-03
NVDA_p2 = daily_adj_closing_prices.iloc[1]['NVDA'] # 2005-01-04
percentage_return = (NVDA_p2 - NVDA_p1) / NVDA_p1
# Alternative:
# percentage_return = NVDA_p2 / NVDA_p1 - 1
NVDA_p1, NVDA_p2, percentage_return # -4.7% change
# Finding the percentage return for all of the stocks in the daily_adj_closing_prices DataFrame.
daily_returns_for_stock_data = daily_adj_closing_prices.iloc[1:] / daily_adj_closing_prices.iloc[:-1].values - 1
# Display first 10 rows of returns.
daily_returns_for_stock_data.loc[:,'ABT':][:10]
An alternative and easier way is to just use the .pct_change() method.
daily_percentage_change_for_stock_data = daily_adj_closing_prices.pct_change()
daily_percentage_change_for_stock_data.iloc[:,:][:10]
# Replace the 'NaN' values with zero and just display the information from the first three stocks.
daily_percentage_change_for_stock_data.fillna(0, inplace=True)
daily_percentage_change_for_stock_data.iloc[:10, :3]
# Obtaining daily percentage change data for one particular stock.
daily_percentage_change_for_stock_data.XOM # XOM
# Alternative:
# daily_percentage_change_for_stock_data['XOM']
Investors use cumulative returns to determine the value of an investment after the investment has been made. It gives periodic insights into the return value relative to the day of investment, and it can be calculated with the .cumprod() method.
More information: https://www.investopedia.com/terms/c/cumulativereturn.asp
daily_cumulative_returns = (1 + daily_percentage_change_for_stock_data).cumprod()
# Display extended rows and columns.
pd.options.display.max_rows = 25 # Extends display limit for rows to 25.
daily_cumulative_returns.iloc[:,:][:]
# The following downloads the data to the local machine and can be used for any DataFrame.
# daily_cumulative_returns.to_csv('daily_cumulative_returns.csv')
# Daily cumulative returns for the various sectors.
energy_sector = daily_cumulative_returns[['HAL', 'APA', 'CVX', 'XOM']].copy()
information_technology_sector = daily_cumulative_returns[['NVDA', 'CSCO', 'ADSK', 'ADBE']].copy()
health_care_sector = daily_cumulative_returns[['ABT', 'ZBH', 'JNJ', 'BAX']].copy()
# Display energy sector data.
energy_sector.plot(figsize=(25, 12), grid=True)
plt.title('Energy Sector Daily Cumulative Returns (HAL, APA, CVX, XOM) from 2005 - 2015')
# Display information technology sector data.
information_technology_sector.plot(figsize=(25, 12), grid=True)
plt.title('Information Technology Sector Daily Cumulative Returns (NVDA, CSCO, ADSK, ADBE) from 2005 - 2015')
# Display health care sector data.
health_care_sector.plot(figsize=(25, 12), grid=True)
plt.title('Health Care Sector Daily Cumulative Returns (ABT, ZBH, JNJ, BAX) from 2005 - 2015')
# Plot cumulative returns for all sectors.
daily_cumulative_returns.plot(figsize=(30, 25), grid=True);
# Opening the image in a new tab will display the chart in a fuller view.
These display the distribution of daily returns for a specific stock.
More Information: https://www.saferpak.com/histogram_articles/howto_histogram.pdf
# Obtaining daily percentage change data for Nvidia stock.
nvda = daily_percentage_change_for_stock_data['NVDA']
# x-axis bins are set to 50
nvda.hist(bins=50, figsize=(20, 15));
# Display summary statistics that describe the histogram.
nvda.describe()
# Obtain information regarding specific percentiles.
nvda.describe(percentiles=[0.05, 0.30, 0.65, 0.95])
# Visualization of all stock distributions.
# Stocks that have a wider distribution in returns are more volatile due to their higher fluctuations.
daily_percentage_change_for_stock_data.hist(bins=50, sharex=True, figsize=(20, 20));
Quantile-Quantile plots are probability plots that compare two distributions by having their quantiles plotted against each other.
More Information: http://data.library.virginia.edu/understanding-q-q-plots/
import scipy.stats as stats
# Plot the returns of NVDA against some random normal values to determine how close the returns are to a normal distribution.
figure = plt.figure(figsize=(20, 15))
axis = figure.add_subplot(111)
stats.probplot(nvda, dist='norm', plot=axis)
axis.grid(True)
plt.show()
Information on interpreting Q-Q plots: https://stats.stackexchange.com/questions/101274/how-to-interpret-a-qq-plot
Represents selections of data by their quartiles.
More Information: http://asq.org/learn-about-quality/data-collection-analysis-tools/overview/box-whisker-plot.html
# Create box-and-whisker plot for Nvidia daily percentage changes.
daily_percentage_change_for_stock_data[['NVDA']].plot(kind='box', figsize=(10, 20), grid=True);
# Plot the distributions for all of the stocks.
daily_percentage_change_for_stock_data.plot(kind='box', figsize=(20, 30), grid=True);
# The more volitile stocks will display a wider box.
Determining the correlation between two stock's daily percentage rates of change in prices can be done through scatter plots.
More Information: https://www.statcan.gc.ca/edu/power-pouvoir/ch9/scatter-nuages/5214827-eng.htm
# This function will plot the values from two stocks.
def display_scatter_plot(stock_data, x_stock, y_stock, x_limit = None, y_limit = None):
figure = plt.figure(figsize=(20, 15))
axis = figure.add_subplot(111)
axis.scatter(stock_data[x_stock], stock_data[y_stock])
if x_limit is not None:
axis.set_xlim(x_limit)
axis.autoscale(False)
axis.vlines(0, -10, 10)
axis.hlines(0, -10, 10)
axis.plot((-10, 10), (-10, 10))
axis.set_xlabel(x_stock)
axis.set_ylabel(y_stock)
limits = [-0.20, 0.20]
# Comparing NVDA and ABT will result in a plot that shows virtually no correlation and quite a few outliers.
display_scatter_plot(daily_percentage_change_for_stock_data, 'NVDA', 'ABT', x_limit=limits)
# This comparison shows a more slightly prominent positive correlation.
display_scatter_plot(daily_percentage_change_for_stock_data, 'NVDA', 'CSCO', x_limit=limits)
# An even greater positive correlation.
display_scatter_plot(daily_percentage_change_for_stock_data, 'HAL', 'CVX', x_limit=limits)
# Comparing all stock relationships against each other to view the various combinations.
pd.plotting.scatter_matrix(daily_percentage_change_for_stock_data, diagonal='kde', alpha=0.1, figsize=(30, 30));
The Pandas library contains a number of functions that allows for the segmentation of data and the calculation of rolling statistics.
More information: https://www.investopedia.com/university/movingaverage/movingaverages1.asp
Documentation: https://pandas.pydata.org/pandas-docs/stable/api.html#standard-moving-window-functions
# If "KeyError: 'Adj Close'" occurs then rerun the first cell after the imports that defines the nvda variable.
nvda = web.get_data_yahoo('NVDA', start, end)
# Obtain the adjusted closing values for Nvidia from 2010.
nvda_adjusted_closing_2010 = nvda['2010']['Adj Close']
nvda_adjusted_closing_2010.head()
nvda_subset_2010 = nvda_adjusted_closing_2010['2010']
# Plot the adjusted closing prices for Nvidia in 2010.
nvda_subset_2010.plot(figsize=(20, 10), grid=True);
# Plot the rolling mean with five periods against the data above.
nvda_subset_2010.plot(figsize=(20, 10))
nvda_subset_2010.rolling(window=5).mean().plot(grid=True);
# Increasing the window value will result in a smoother line but with less accuracy.
nvda_subset_2010.plot(figsize=(20, 10))
nvda_subset_2010.rolling(window=10).mean().plot(grid=True)
nvda_subset_2010.rolling(window=30).mean().plot(grid=True);
There is also a rolling correlation function that can be used to find how the correlation between two stocks has changed over time.
# Calculate and visualize the change in correlation between ABT and XOM based on their daily percentage returns.
# '\' is used to split the code for readability.
rolling_correlation_ABT_XOM = daily_percentage_change_for_stock_data.ABT. \
rolling(window=252).corr(other=daily_percentage_change_for_stock_data.XOM).dropna() # 252 for an annualized period
rolling_correlation_ABT_XOM.plot(figsize=(20, 10), grid=True);
A stock's volatility, or risk, can be determined by analyzing its fluctuating variance over a time period.
More information: https://www.investopedia.com/terms/v/volatility.asp
# Calculate volatility for Nvidia with 30 day windows.
nvda_volatility_30 = daily_percentage_change_for_stock_data.NVDA.rolling(window=30).std() * np.sqrt(30)
nvda_volatility_30.plot(figsize=(20, 10), grid=True);
# Calculate annualized volatility for Nvidia.
nvda_volatility_annualized = daily_percentage_change_for_stock_data.NVDA.rolling(window=252).std() * np.sqrt(252)
nvda_volatility_annualized.plot(figsize=(20, 10), grid=True);
# Comparing volatility in the information technology sector given a window of 100 days.
nvda_volatility = daily_percentage_change_for_stock_data.NVDA.rolling(window=100).std() * np.sqrt(100)
csco_volatility = daily_percentage_change_for_stock_data.CSCO.rolling(window=100).std() * np.sqrt(100)
adsk_volatility = daily_percentage_change_for_stock_data.ADSK.rolling(window=100).std() * np.sqrt(100)
adbe_volatility = daily_percentage_change_for_stock_data.ADBE.rolling(window=100).std() * np.sqrt(100)
nvda_volatility.plot(figsize=(20, 10), grid=True)
csco_volatility.plot(figsize=(20, 10), grid=True)
adsk_volatility.plot(figsize=(20, 10), grid=True)
adbe_volatility.plot(figsize=(20, 10), grid=True)
plt.legend()
The Python package pyfinance contains an ordinary least squares function that can be used to calculate the change in volatility between two stocks.
More Information: https://www.investopedia.com/terms/l/least-squares-method.asp
Documentation: https://pypi.python.org/pypi/pyfinance
from pyfinance.ols import PandasRollingOLS
pd.set_option('display.max_rows', 15)
# NVDA and XOM are used in this example.
model = PandasRollingOLS(y=daily_percentage_change_for_stock_data.NVDA, x=daily_percentage_change_for_stock_data.XOM, window=200)
# The coefficients
model.beta
# R-squared
model.rsq
model.beta.plot(figsize=(20, 10), grid=True);
An alternative using the Python module statsmodels.
More Information: http://www.statsmodels.org/dev/examples/notebooks/generated/ols.html
Documentation: http://www.statsmodels.org/dev/generated/statsmodels.regression.linear_model.OLS.html
import statsmodels.api as sm
model2 = sm.OLS(daily_percentage_change_for_stock_data['NVDA'], daily_percentage_change_for_stock_data['XOM'])
fit = model2.fit()
fit.summary()
Comparing stocks against the Standard & Poor's 500 Index will demonstrate to some degree how certain securities compare to market as a whole.
More Information: https://www.investopedia.com/ask/answers/040215/what-does-sp-500-index-measure-and-how-it-calculated.asp
# Calculate the daily percentage change for the S&P 500 data obtain earlier on in the beginning of this section.
sp500_daily_percentage_change = sp500['Adj Close'].pct_change().fillna(0)
sp500_daily_percentage_change
# Combine daily percentage change for all of the stock data with the daily percentage change for the S&P 500 in a new DataFrame.
daily_percentage_change_stocks_sp500 = pd.concat([sp500_daily_percentage_change,
daily_percentage_change_for_stock_data], axis=1)
daily_percentage_change_stocks_sp500.rename(columns={'Adj Close': 'SP500'}, inplace=True)
daily_percentage_change_stocks_sp500
# Calculate cumulative daily returns.
cumulative_daily_returns_stocks_sp500 = (1 + daily_percentage_change_stocks_sp500).cumprod()
cumulative_daily_returns_stocks_sp500
# Plot the cumulative daily returns with all of the data.
cumulative_daily_returns_stocks_sp500.plot(figsize=(20, 15), grid=True);
# Calculate the correlation of all available daily values.
pd.options.display.max_columns = None
pd.options.display.max_rows = None
dpc_stocks_sp500_correlation = daily_percentage_change_stocks_sp500.corr()
dpc_stocks_sp500_correlation
# Display the data in a more formated way.
from IPython.display import display, HTML
display(HTML(dpc_stocks_sp500_correlation.to_html()))
# Displaying the correlations of the S&P 500.
display(dpc_stocks_sp500_correlation.SP500)
CVX (0.778) had movements most comparable to the S&P while BAX (0.558) showed the least similarities.
These stocks can be plotted to visualize the differences in activity and their relationship to the S&P 500.
cumulative_daily_returns_stocks_sp500[['SP500', 'CVX', 'BAX']].plot(figsize=(25 ,15));
# The tighter distribution of points reflects the 0.778 correlation value.
display_scatter_plot(daily_percentage_change_stocks_sp500, 'SP500', 'CVX')
# The correlation is significantly less prominent for BAX given the wider distribution.
display_scatter_plot(daily_percentage_change_stocks_sp500, 'SP500', 'BAX')
# If executed after plot creations then this command will save all prior plots on the local machine.
# plt.savefig('Image.png', bbox_inches='tight', dpi=300)
import quandl
pd.set_option('display.max_rows', 15)
# An API key was set up for this project in order to give access to Quandl datasets.
quandl.ApiConfig.api_key = 'Ny25TbU6ui7fgDhweAhR'
# Obtain London Stock Exchange Prices.
quandl.get('XLON/AEO', start_date='2007-07-11', end_date='2017-05-15')
# Get AMD stock data.
amd_stock = quandl.get('WIKI/AMD')
amd_stock
amd_stock['Adj. Close'].plot(figsize=(20, 8));
# Downloads the data locally into a csv file.
# amd_stock.to_csv('AMD_Stock.csv')
More Information: https://www.quandl.com/tools/python
Documentation: https://docs.quandl.com/docs/getting-started
In a new notebook try and recreate this section using different datasets obtained from Quandl. Explore the various techniques covered so far by adjusting the parameters and input data.
AMERICAN SOCIETY FOR QUALITY. (n.d.). Box and Whisker Plot. Retrieved from asq.org: http://asq.org/learn-about-quality/data-collection-analysis-tools/overview/box-whisker-plot.html
Ford, C. (2015, August 26). Understanding Q-Q Plots. Retrieved from http://data.library.virginia.edu: http://data.library.virginia.edu/understanding-q-q-plots/
Glen_b. (2014, June 5). How to interpret a QQ plot. Retrieved from stats.stackexchange.com: https://stats.stackexchange.com/questions/101274/how-to-interpret-a-qq-plot
Heydt, M. (2015). Mastering pandas for Finance. Birmingham, United Kingdom: Packt Publishing Ltd.
Investopedia. (2015, April 2). What does the S&P 500 index measure and how is it calculated? Retrieved from investopedia.com: https://www.investopedia.com/ask/answers/040215/what-does-sp-500-index-measure-and-how-it-calculated.asp
Investopedia. (2016, May 17). Least Squares Method. Retrieved from investopedia.com: https://www.investopedia.com/terms/l/least-squares-method.asp
Investopedia. (2016, August 4). Volatility. Retrieved from investopedia.com: https://www.investopedia.com/terms/v/volatility.asp
Investopedia. (2017, November 9). Beta. Retrieved from investopedia.com: https://www.investopedia.com/terms/b/beta.asp
Investopedia. (2018, March 27). Cumulative Return. Retrieved from investopedia.com: https://www.investopedia.com/terms/c/cumulativereturn.asp
Josef Perktold, S. S. (2017, February 9). Ordinary Least Squares, 0.8.0. Retrieved from statsmodels.org: http://www.statsmodels.org/dev/examples/notebooks/generated/ols.html
Josef Perktold, S. S. (2017, February 9). statsmodels.regression.linear_model.OLS, 0.8.0. Retrieved from statsmodels.org: http://www.statsmodels.org/dev/generated/statsmodels.regression.linear_model.OLS.html
Michael Droettboom, T. A. (2018, April 12). matplotlib.dates, 2.2.2. Retrieved from matplotlib.org: https://matplotlib.org/api/dates_api.html
Murphy, C. (2018, April 2). Moving Averages: What Are They? Retrieved from investopedia.com: https://www.investopedia.com/university/movingaverage/movingaverages1.asp
NumFOCUS. (2017, December 30). Standard moving window functions, 0.22.0. Retrieved from pandas.pydata.org: https://pandas.pydata.org/pandas-docs/stable/api.html#standard-moving-window-functions
Python Software Foundation. (2018, February 9). Yahoo! Finance Fix for Pandas Datareader. Retrieved from pypi.python.org: https://pypi.python.org/pypi/fix-yahoo-finance
Quandl. (2017). Get Financial Data Directly into Python. Retrieved from quandl.com: https://www.quandl.com/tools/python
Quandl. (n.d.). How to get started with Quandl's API. Retrieved from docs.quandl.comauthor: https://docs.quandl.com/docs/getting-started
Saferpak. (2003, Hune 16). Basic Tools for Process Improvement. Retrieved from saferpak.com: https://www.saferpak.com/histogram_articles/howto_histogram.pdf
Solomon, B. (2018, March 27). pyfinance 1.0.1, 1.0.1. Retrieved from pypi.python.org: https://pypi.python.org/pypi/pyfinance Statistics Canada. (2013, July 23). Scatterplots. Retrieved from statcan.gc.ca: https://www.statcan.gc.ca/edu/power-pouvoir/ch9/scatter-nuages/5214827-eng.htm
StockCharts. (n.d.). Introduction to Candlesticks. Retrieved from stockcharts.com: http://stockcharts.com/school/doku.php?id=chart_school:chart_analysis:introduction_to_candlesticks